package com.xbongbong.paas.data.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.data.service.SerialNoService;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.PaasFormEntity;
import com.xbongbong.paas.domain.entity.PaasFormExplainEntity;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.SheetTypeEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.field.SerialNumberPoJo;
import com.xbongbong.paas.help.ProFormHelp;
import com.xbongbong.paas.help.RepeatHelp;
import com.xbongbong.paas.help.SerialNoHelp;
import com.xbongbong.paas.log.MongoLogHelp;
import com.xbongbong.paas.log.constant.LogMemoConstant;
import com.xbongbong.paas.model.PaasFormExplainModel;
import com.xbongbong.paas.model.PaasFormModel;
import com.xbongbong.paas.pojo.dto.FormDataAddDTO;
import com.xbongbong.paas.pojo.dto.FormDataRepeatDTO;
import com.xbongbong.paas.pojo.dto.FormUpdateDTO;
import com.xbongbong.paas.pojo.dto.SerialNoDTO;
import com.xbongbong.paas.pojo.dto.SerialNoListDTO;
import com.xbongbong.paas.pojo.vo.SerialNoListVO;
import com.xbongbong.paas.pojo.vo.SerialNoSetVO;
import com.xbongbong.paas.pojo.vo.SerialNoVO;
import com.xbongbong.paas.redis.PaasRedisHelper;
import com.xbongbong.paas.redis.RedisPrefixConstant;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.parent.util.SerialNoUtil;
import com.xbongbong.pro.enums.DistributorMarkEnum;
import com.xbongbong.pro.enums.ErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.BuinessDefaultErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.TemplateErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.enums.OperateModuleTypeEnum;
import com.xbongbong.saas.enums.OperateTypeEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ProductEnum;
import com.xbongbong.saas.enums.business.QuotationEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author: wufeng
 * @date: 2018/9/12 17:07
 * @desrcption:
 */
@Service("serialNoService")
public class SerialNoServiceImpl implements SerialNoService {

    private static final Logger LOG = LoggerFactory.getLogger(SerialNoServiceImpl.class);

    @Resource
    private PaasRedisHelper paasRedisHelper;
    @Resource
    private PaasFormExplainModel paasFormExplainModel;
    @Resource
    private SerialNoHelp serialNoHelp;
    @Resource
    private PaasFormModel paasFormModel;
    @Resource
    private MongoLogHelp mongoLogHelp;
    @Resource
    private RepeatHelp repeatHelp;
    @Resource
    private ProFormHelp proFormHelp;

    /**
     * 获取流水好列表
     *
     * @param serialNoListDTO
     * @return
     * @throws XbbException
     */
    @Override
    public SerialNoListVO getSerialNoList(SerialNoListDTO serialNoListDTO) throws XbbException {
        SerialNoListVO serialNoVO = new SerialNoListVO();
        List<String> serialNoList = new ArrayList<>();
        String corpid = serialNoListDTO.getCorpid();
        SerialNumberPoJo serialNumber = null;
        Integer businessType = serialNoListDTO.getBusinessType();
        Integer linkBusinessType = serialNoListDTO.getLinkBusinessType();
        SheetTypeEnum sheetTypeEnum = SheetTypeEnum.getByBusinessType(serialNoListDTO.getBusinessType());
        boolean sheetFlag = SheetTypeEnum.validateSheet(sheetTypeEnum);
        if (sheetFlag) {
            businessType = sheetTypeEnum.getXbbRefTypeEnum().getCode();
        }
        Integer distributorMark = serialNoListDTO.getDistributorMark() == null ? DistributorMarkEnum.OTHER.getCode() : serialNoListDTO.getDistributorMark();
        serialNoListDTO.setDistributorMark(distributorMark);
        PaasFormExplainEntity paasFormExplainEntity;
        if (Objects.equals(linkBusinessType, XbbRefTypeEnum.PAY_PLAN.getCode())){
            paasFormExplainEntity = paasFormExplainModel.getByBusinessType4Distributor(linkBusinessType, corpid, distributorMark);
        }else {
            paasFormExplainEntity = paasFormExplainModel.getByBusinessType4Distributor(businessType, corpid, distributorMark);
        }

        if ( paasFormExplainEntity==null ){
            throw new XbbException(TemplateErrorCodeEnum.API_ERROR_350002.getCode(),TemplateErrorCodeEnum.API_ERROR_350002.getMsg());
        }
        List<FieldAttrEntity> explainList = JSONArray.parseArray(paasFormExplainEntity.getExplains(), FieldAttrEntity.class);
        Boolean flag = true;
        serialNoVO.setStrictController(BasicConstant.ZERO);
        for ( FieldAttrEntity fieldAttrEntity : explainList ) {
            if ( fieldAttrEntity.getFieldType() != null && fieldAttrEntity.getFieldType().equals(FieldTypeEnum.SERIALNO.getType()) ) {
                serialNumber = fieldAttrEntity.getSerialNumber();
                if (Objects.equals(fieldAttrEntity.getStrictController(), BasicConstant.ONE)){
                    flag = false;
                    serialNoVO.setStrictController(BasicConstant.ONE);
                }
                break;
            }
        }

        if ( Objects.nonNull(serialNumber) && flag ) {
            try {
                String time = "";
                int cacheSeconds = 0;
                // 时间类型
                time = serialNoHelp.getPrefixTime(serialNumber, time);
                // 缓存时间
                cacheSeconds = serialNoHelp.getSerialNoCache(serialNumber);
                // 前缀
                String prefix = serialNumber.getPrefix();
                // 后缀
                String postfix = serialNumber.getPostfix();
                // 自增位数
                Integer numberDigit = serialNumber.getNumberDigit();
                if ( numberDigit < PaasConstant.DEFUALT_NUMBER_DIGIT ) {
                    numberDigit = PaasConstant.DEFUALT_NUMBER_DIGIT;
                }
                // 自增起始值
                Integer startNum = serialNumber.getStartNum();
                if ( startNum == null || startNum < 0 ) {
                    startNum = 1;
                }
                String timeS ="";
                timeS = serialNoHelp.getSeriTime(serialNumber, timeS);
                String filePrefix = RedisPrefixConstant.SERIAL_NO_PREFIX + prefix + timeS;
                String key = corpid + paasFormExplainEntity.getFormId().toString();
                for ( int i = 1; i <= serialNoListDTO.getCount(); i++ ) {
                    Long incrNumber = paasRedisHelper.getIncrNumByOne(filePrefix, key, cacheSeconds, startNum);
                    String decimalFormatStr = "%0" + numberDigit + "d";
                    String incrNumberFormat = String.format(decimalFormatStr, incrNumber);
                    String serialNo = prefix + time + incrNumberFormat + postfix;
                    serialNoList.add(serialNo);
                }
            } catch (Exception e) {
                LOG.error("SerialNoUtil获取流水号失败", e);
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
            }
        }
        serialNoVO.setSerialNoList(serialNoList);
        return serialNoVO;
    }

    /**
     * 设置流水号
     * @param formUpdateDTO
     * @return
     * @throws XbbException
     */
    @Override
    public SerialNoSetVO setSerialNo(FormUpdateDTO formUpdateDTO) throws XbbException {
        SerialNoSetVO serialNoSetVO = new SerialNoSetVO();
        try {
            SerialNumberPoJo serialNumber = null;
            List<FieldAttrEntity> explainList = formUpdateDTO.getExplainList();
            for (int i = 0; i < explainList.size(); i++) {
                FieldAttrEntity fieldAttrEntity = explainList.get(i);
                // 获取流水号
                if(Objects.equals(fieldAttrEntity.getAttr(), FieldTypeEnum.SERIALNO.getAlias())){
                    serialNumber = fieldAttrEntity.getSerialNumber();
                    break;
                }
            }
            if (Objects.isNull(serialNumber)) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
            }
            String corpid = formUpdateDTO.getCorpid();
            String timeS ="";
            timeS = serialNoHelp.getSeriTime(serialNumber, timeS);
            // 前缀
            String prefix = serialNumber.getPrefix();
            String filePrefix = RedisPrefixConstant.SERIAL_NO_PREFIX + prefix + timeS;
            Long formId = formUpdateDTO.getFormId();
            if (Objects.isNull(formId)) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100002);
            }
            String key = corpid + formId.toString();

            paasRedisHelper.removeValue(filePrefix, key);
        } catch (XbbException e ) {
            throw e;
        } catch (Exception e ) {
            LOG.error("serialNoService设置流水号失败", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
        return serialNoSetVO;
    }

    /**
     * 开启严控后流水号生成
     * @param formDataSaveDTO
     * @param corpid
     * @param businessType
     * @param explainMap
     * @return
     * @throws XbbException
     */
    @Override
    public PaasFormDataEntity setSerialNo(FormDataAddDTO formDataSaveDTO, String corpid, Integer businessType, Map<String, FieldAttrEntity> explainMap) throws XbbException {
        PaasFormDataEntity paasFormDataEntity = new PaasFormDataEntity();
        Integer isImport = formDataSaveDTO.getIsImport();
        FieldAttrEntity fieldAttrEntity = explainMap.get(FieldTypeEnum.SERIALNO.getAlias());
        // 报价单新版本导入不需要改变流水号
        Boolean flag = true;
        if (Objects.equals(isImport, BasicConstant.ONE) && Objects.equals(businessType, XbbRefTypeEnum.QUOTATION.getCode()) && Objects.nonNull(formDataSaveDTO.getGroupNumber())){
            Integer version = Integer.parseInt(formDataSaveDTO.getSerialNo().substring(formDataSaveDTO.getGroupNumber().length(), formDataSaveDTO.getGroupNumber().length()+1));
            if (!Objects.equals(version, BasicConstant.ONE)){
                flag =false;
            }
        }
        if (SerialNoUtil.isToCreateSerialNo(formDataSaveDTO.getGroupNumber(), formDataSaveDTO.getIsImport(), formDataSaveDTO.getSerialNo(), businessType, fieldAttrEntity) && flag) {
            getSerialNo(formDataSaveDTO, corpid, fieldAttrEntity);
            JSONObject dataList = formDataSaveDTO.getDataList();
            if ( Objects.equals(businessType, XbbRefTypeEnum.QUOTATION.getCode()) ) {
                // 报价单编号是组号加版本号
                formDataSaveDTO.setGroupNumber(formDataSaveDTO.getSerialNo());
                // 生成的编号有已含有版本号，截取后缀前内容为组号
                String quotationSerialNo = formDataSaveDTO.getSerialNo();
                String[] serialNoSplit = quotationSerialNo.split(fieldAttrEntity.getSerialNumber().getPostfix());
                dataList.put(QuotationEnum.VERSION.getAttr(), StringConstant.DEFAULT_VERSION);
                dataList.put(QuotationEnum.QUOTATION_NO.getAttr(), quotationSerialNo);
                if (serialNoSplit != null && serialNoSplit.length == BasicConstant.TWO) {
                    //可能不存在后缀值
                    dataList.put(QuotationEnum.GROUP_NUMBER.getAttr(), serialNoSplit[0] + fieldAttrEntity.getSerialNumber().getPostfix());
                } else {
                    dataList.put(QuotationEnum.GROUP_NUMBER.getAttr(), formDataSaveDTO.getGroupNumber());
                }
                paasFormDataEntity.setData(dataList);
                formDataSaveDTO.setSerialNo(quotationSerialNo);
            } else if (Objects.equals(businessType, XbbRefTypeEnum.PRODUCT.getCode())){
                dataList.put(FieldTypeEnum.SERIALNO.getAlias(), formDataSaveDTO.getSerialNo());
                paasFormDataEntity.setSerialNo(formDataSaveDTO.getSerialNo());
                paasFormDataEntity.setData(dataList);
                // 规格字段是否启用
                FieldAttrEntity speification = explainMap.get(ProductEnum.SPECIFICATION.getAttr());
                if (Objects.nonNull(speification) && Objects.equals(speification.getIsOpen(), BasicConstant.ONE)) {
                    JSONObject map = dataList.getJSONObject(ProductEnum.SPECIFICATION.getAttr());
                    Integer num = 0;
                    if (Objects.nonNull(map)) {
                        JSONArray specDetails = (JSONArray) map.get("specDetails");
                        if (Objects.nonNull(specDetails)) {
                            for (Object specDetail : specDetails) {
                                JSONObject specDetail1 = (JSONObject) specDetail;
                                specDetail1.put("specCode", formDataSaveDTO.getSerialNo() + "." + num);
                                num++;
                            }
                        }
                    }
                    dataList.put(ProductEnum.SPECIFICATION.getAttr(), map);
                }
                paasFormDataEntity.setData(dataList);
            }else {
                dataList.put(FieldTypeEnum.SERIALNO.getAlias(),formDataSaveDTO.getSerialNo());
                paasFormDataEntity.setData(dataList);
                paasFormDataEntity.setSerialNo(formDataSaveDTO.getSerialNo());
            }
        }
        return paasFormDataEntity;
    }

    /**
     * 开启严控模式后，生成相应的流水号
     * @param formDataSaveDTO
     * @param corpid
     * @param fieldAttrEntity
     * @throws XbbException
     */
    @Override
    public String getSerialNo(FormDataAddDTO formDataSaveDTO, String corpid, FieldAttrEntity fieldAttrEntity) throws XbbException {
        if (Objects.nonNull(fieldAttrEntity)){
            if (Objects.equals(fieldAttrEntity.getStrictController(), BasicConstant.ONE)){
                // 校验流水号是否重复
                Boolean flag = false;
                Boolean isQuotation = false;
                if (Objects.equals(formDataSaveDTO.getBusinessType(), XbbRefTypeEnum.QUOTATION.getCode())){
                    isQuotation = true;
                }
                String serialNo = "";
                while (!flag){
                    serialNo = getSerialNo(corpid, formDataSaveDTO.getFormId(), fieldAttrEntity);
                    if (isQuotation){
                        serialNo = serialNo+StringConstant.DEFAULT_VERSION;
                    }
                    formDataSaveDTO.setSerialNo(serialNo);
                    // 校验流水号是否重复
                    FormDataRepeatDTO formDataRepeatDTO = new FormDataRepeatDTO();
                    BeanUtil.copyProperties(formDataSaveDTO,formDataRepeatDTO);
                    formDataRepeatDTO.setSerialNo(serialNo);
                    formDataRepeatDTO.setAttr(FieldTypeEnum.SERIALNO.getAlias());
                    formDataRepeatDTO.setValue(serialNo);
                    flag = repeatHelp.repeat(formDataRepeatDTO).getNoRepeat();
                    if ( flag ) {
                        if ( Objects.nonNull(formDataSaveDTO.getFormId()) ) {
                            PaasFormEntity paasFormEntityExt = proFormHelp.getPaasForm(formDataSaveDTO.getFormId(), formDataSaveDTO.getBusinessType(), corpid);
                            String userId = Objects.toString(formDataSaveDTO.getUserId(), "");
                            String userName = Objects.toString(formDataSaveDTO.getLoginUserName(), "");
                            // 记录日志
                            String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_CREATE_SERIAL_NO), userName, paasFormEntityExt.getName(), serialNo);
                            mongoLogHelp.buildLog(corpid, userId, userName, OperateModuleTypeEnum.SERIAL_NO, OperateTypeEnum.NEW, paasFormEntityExt.getId().toString(), paasFormEntityExt.getName(), memo, formDataSaveDTO.getHttpHeader());

                        }
                    }
                }
                return serialNo;
            }
        }
        return formDataSaveDTO.getSerialNo();
    }

    /**
     * 生成流水号
     * @param corpid 公司id
     * @param formId 表单id
     * @param fieldAttrEntity 字段实体
     * @return java.lang.String
     * @throws XbbException
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    @Override
    public String getSerialNo(String corpid, Long formId, FieldAttrEntity fieldAttrEntity) throws XbbException {
        String serialNo="";
        if (fieldAttrEntity.getFieldType() != null && fieldAttrEntity.getFieldType().equals(FieldTypeEnum.SERIALNO.getType())) {
            SerialNoDTO serialNoDTO = new SerialNoDTO();
            serialNoDTO.setCorpid(corpid);
            serialNoDTO.setFormId(formId);
            serialNoDTO.setSerialNumber(fieldAttrEntity.getSerialNumber());
            // 生成流水号
            SerialNoVO serialNoVO = serialNoHelp.getSerialNo(serialNoDTO);
            if (serialNoVO == null || StringUtil.isEmpty(serialNoVO.getSerialNo())) {
                throw new XbbException(BuinessDefaultErrorCodeEnum.API_ERROR_200026);
            }

            serialNo = serialNoVO.getSerialNo();
        }
        return serialNo;
    }
}
